package cn.sxgan.gen.utils;

import java.util.HashMap;
import java.util.Map;

/**
 * JDBC类型到Java类型转换工具类
 */
public class JdbcTypeConverterUtils {

    // 类型映射缓存
    private static final Map<String, String> TYPE_MAP = new HashMap<>();
    
    static {
        // 初始化类型映射
        initTypeMap();
    }

    private static void initTypeMap() {
        // 数字类型
        TYPE_MAP.put("TINYINT", "Byte");
        TYPE_MAP.put("SMALLINT", "Short");
        TYPE_MAP.put("INTEGER", "Integer");
        TYPE_MAP.put("INT", "Integer");
        TYPE_MAP.put("BIGINT", "Long");
        TYPE_MAP.put("FLOAT", "Float");
        TYPE_MAP.put("REAL", "Float");
        TYPE_MAP.put("DOUBLE", "Double");
        TYPE_MAP.put("NUMERIC", "BigDecimal");
        TYPE_MAP.put("DECIMAL", "BigDecimal");
        TYPE_MAP.put("NUMBER", "BigDecimal");
        
        // 字符串类型
        TYPE_MAP.put("CHAR", "String");
        TYPE_MAP.put("VARCHAR", "String");
        TYPE_MAP.put("LONGVARCHAR", "String");
        TYPE_MAP.put("NCHAR", "String");
        TYPE_MAP.put("NVARCHAR", "String");
        TYPE_MAP.put("LONGNVARCHAR", "String");
        TYPE_MAP.put("CLOB", "String");
        TYPE_MAP.put("NCLOB", "String");
        TYPE_MAP.put("TEXT", "String");
        
        // 日期时间类型
        TYPE_MAP.put("DATE", "LocalDate");
        TYPE_MAP.put("TIME", "LocalTime");
        TYPE_MAP.put("DATETIME", "LocalDateTime");
        TYPE_MAP.put("TIMESTAMP", "LocalDateTime");
        TYPE_MAP.put("TIMESTAMPTZ", "java.time.OffsetDateTime"); // PostgreSQL带时区的时间戳
        
        // 二进制类型
        TYPE_MAP.put("BINARY", "byte[]");
        TYPE_MAP.put("VARBINARY", "byte[]");
        TYPE_MAP.put("LONGVARBINARY", "byte[]");
        TYPE_MAP.put("BLOB", "byte[]");
        
        // 布尔类型
        TYPE_MAP.put("BIT", "Boolean");
        TYPE_MAP.put("BOOLEAN", "Boolean");
        TYPE_MAP.put("BOOL", "Boolean");
        
        // 其他类型
        TYPE_MAP.put("ROWID", "String");
        TYPE_MAP.put("SQLXML", "String");
        TYPE_MAP.put("ARRAY", "java.sql.Array");
        TYPE_MAP.put("REF", "java.sql.Ref");
        TYPE_MAP.put("STRUCT", "java.sql.Struct");
    }

    /**
     * 将JDBC类型字符串转换为Java类型字符串
     * 
     * @param jdbcType JDBC类型字符串 (如 "VARCHAR", "INT", "TIMESTAMP")
     * @return Java类型字符串 (如 "String", "Integer", "LocalDateTime")
     */
    public static String convertToJavaType(String jdbcType) {
        if (jdbcType == null || jdbcType.isEmpty()) {
            return "Object";
        }
        
        // 标准化输入：转为大写，并移除多余空格和括号
        String normalizedType = normalizeJdbcType(jdbcType);
        
        // 查找映射
        String javaType = TYPE_MAP.get(normalizedType);
        
        // 处理带长度的类型（如 VARCHAR(255)）
        if (javaType == null && normalizedType.startsWith("VARCHAR")) {
            return "String";
        }
        
        // 处理带精度的数字类型（如 DECIMAL(10,2)）
        if (javaType == null && (normalizedType.startsWith("NUMERIC") || 
                                 normalizedType.startsWith("DECIMAL"))) {
            return "BigDecimal";
        }
        
        // 处理MySQL的TINYINT(1)作为布尔值的情况
        if (javaType == null && normalizedType.startsWith("TINYINT(1)")) {
            return "Boolean";
        }
        
        // 处理Oracle的特定类型
        if (javaType == null && normalizedType.startsWith("VARCHAR2")) {
            return "String";
        }
        
        return javaType != null ? javaType : "Object";
    }
    
    /**
     * 标准化JDBC类型字符串
     * 
     * @param jdbcType 原始JDBC类型字符串
     * @return 标准化后的类型字符串
     */
    private static String normalizeJdbcType(String jdbcType) {
        // 转换为大写
        String type = jdbcType.toUpperCase();
        
        // 移除括号及其内容（如 VARCHAR(255) -> VARCHAR）
        int parenIndex = type.indexOf('(');
        if (parenIndex != -1) {
            type = type.substring(0, parenIndex);
        }
        
        // 移除空格
        type = type.replaceAll("\\s", "");
        
        return type;
    }
    
    /**
     * 获取完整的Java类型（包含包名）
     * 
     * @param jdbcType JDBC类型字符串
     * @return 完整的Java类型（如 "java.lang.String", "java.time.LocalDateTime"）
     */
    public static String getFullJavaType(String jdbcType) {
        String simpleType = convertToJavaType(jdbcType);
        return getFullTypeName(simpleType);
    }
    
    /**
     * 根据简单类型名获取完整类型名
     * 
     * @param simpleType 简单类型名
     * @return 完整类型名
     */
    private static String getFullTypeName(String simpleType) {
        switch (simpleType) {
            case "Byte":
            case "Short":
            case "Integer":
            case "Long":
            case "Float":
            case "Double":
            case "Boolean":
            case "Character":
                return "java.lang." + simpleType;
            case "BigDecimal":
                return "java.math.BigDecimal";
            case "LocalDate":
            case "LocalTime":
            case "LocalDateTime":
                return "java.time." + simpleType;
            case "byte[]":
                return "byte[]";
            default:
                return simpleType.equals("Object") ? "java.lang.Object" : simpleType;
        }
    }

    /**
     * 判断是否需要导入java.time包
     * 
     * @param jdbcType JDBC类型字符串
     * @return 是否需要导入时间包
     */
    public static boolean requiresTimeImport(String jdbcType) {
        String javaType = convertToJavaType(jdbcType);
        return javaType.equals("LocalDate") || 
               javaType.equals("LocalTime") || 
               javaType.equals("LocalDateTime");
    }
    
    /**
     * 判断是否需要导入java.math包
     * 
     * @param jdbcType JDBC类型字符串
     * @return 是否需要导入数学包
     */
    public static boolean requiresMathImport(String jdbcType) {
        String javaType = convertToJavaType(jdbcType);
        return javaType.equals("BigDecimal");
    }
    
    /**
     * 测试方法
     */
    public static void main(String[] args) {
        testConversion("INT", "Integer");
        testConversion("VARCHAR(255)", "String");
        testConversion("DECIMAL(10,2)", "BigDecimal");
        testConversion("TIMESTAMP", "LocalDateTime");
        testConversion("BOOLEAN", "Boolean");
        testConversion("BLOB", "byte[]");
        testConversion("DATE", "LocalDate");
        testConversion("TINYINT(1)", "Boolean");
        testConversion("NUMBER", "BigDecimal");
        testConversion("VARCHAR2", "String");
        testConversion("UNKNOWN_TYPE", "Object");
    }
    
    private static void testConversion(String jdbcType, String expectedJavaType) {
        String javaType = convertToJavaType(jdbcType);
        String fullType = getFullJavaType(jdbcType);
        System.out.printf("JDBC: %-15s -> Java: %-15s Full: %-25s %s%n",
                jdbcType, 
                javaType, 
                fullType,
                javaType.equals(expectedJavaType) ? "✓" : "✗ (Expected: " + expectedJavaType + ")");
    }
}